Skip to content

fix: prevent replayed signed reads#386

Open
matthias-wright wants to merge 5 commits into
veridise-audit-april-2026from
m/m/signed-reads-replay-protection
Open

fix: prevent replayed signed reads#386
matthias-wright wants to merge 5 commits into
veridise-audit-april-2026from
m/m/signed-reads-replay-protection

Conversation

@matthias-wright
Copy link
Copy Markdown
Contributor

Prevents replays of signed reads by validating recent_block_hash and expires_at_block on eth_call / eth_estimateGas / eth_simulateV1 before decryption.

Changes:

  • New validate_seismic_freshness helper, called from signed_read_to_plaintext_tx so all three signed-read endpoint hit the same check.
  • Moves SEISMIC_TX_RECENT_BLOCK_LOOKBACK to reth-seismic-primitives (txpool keeps a re-export) so RPC and
    pool share one variable.
  • Adds unit tests.

samlaf and others added 4 commits April 22, 2026 13:36
Signed-read seismic transactions were previously rejected only at mempool
admission. Block producers ingesting txs through non-mempool paths —
builder API, private orderflow, or the EIP-712 `TypedData` variant of
`eth_sendRawTransaction` which bypassed `Decodable2718` — could include a
signed-read tx directly, letting an attacker who intercepted a signed
`eth_call` payload replay it as an actual state-changing transaction.

Consumes seismic-alloy's decoder-level rejection (#104, c1ce533) and
updates this crate accordingly:

* `send_raw_transaction`: the `TypedData` arm now decodes the EIP-712
  payload into a `SeismicTxEnvelope`, re-encodes as RLP, and delegates to
  `EthTransactions::send_raw_transaction(bytes)`. All signed-tx ingress
  now funnels through a single `Decodable2718::typed_decode` pipeline, so
  decode-time invariants (including the new signed-read rejection) apply
  uniformly. Removes the parallel pool-admission pipeline that was the
  bypass.

* For `eth_call`'s Bytes path, a new `recover_raw_seismic_call_tx` helper
  uses seismic-alloy's permissive `decode_2718_permit_seismic_calls` so
  legitimate signed-read payloads are still accepted.

* Removes the now-redundant mempool-level `validate_signed_read_for_write`
  check and its associated error variant.

Depends on seismic-alloy PR #104; the \`rev\` in Cargo.toml is temporary and
should be bumped to the merged-main commit before landing.
@matthias-wright matthias-wright requested a review from cdrappi as a code owner May 6, 2026 20:59
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 6, 2026

Refactors Seismic RPC to use upstream reth's FullEthApi trait instead of custom FullSeismicApi, adds comprehensive freshness validation for signed reads, and simplifies transaction sending by handling EIP-712 -> RLP conversion inline.

Phase 1

  • crates/seismic/txpool/src/validator.rs:107-112 — The TODO comment highlights a security gap: freshness validation (recent_block_hash and expires_at_block checks) only runs in the mempool, meaning signed reads can bypass these checks via builder API or other non-mempool paths. This could allow stale/expired signed reads to be included in blocks directly.

Phase 2

  • crates/seismic/rpc/src/eth/utils.rs:540-580 — The freshness validation logic is well-implemented with proper canonical chain verification and comprehensive test coverage. However, it's only applied to RPC paths while the txpool still has its own similar validation logic in validator.rs:115-131. Consider consolidating these to avoid potential inconsistency.
  • crates/seismic/rpc/src/eth/ext.rs:302-304 — The TypedData -> RLP conversion path uses bare .map_err(|_| ...) which discards the original decode error. Consider preserving the error details for debugging: .map_err(|e| EthApiError::FailedToDecodeSignedTransaction.with_context(e.to_string())) or similar.

Phase 3

  • crates/seismic/rpc/src/eth/mod.rs:117-131 — The placeholder try_build_and_sign implementation creates a hardcoded legacy transaction. The TODO comment indicates this needs proper signing logic before production use.

@matthias-wright matthias-wright changed the base branch from seismic to veridise-audit-april-2026 May 6, 2026 21:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants